#include <stdio.h>
#include <string.h>
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "sdkconfig.h"
#include "nvs_flash.h"
#include "esp_system.h"
#include "driver/uart.h"

#include "RCS_protocol.h"
#include "RCS_master.h"
#include "RCS_btn.h"
#include "RCS_fire.h"
#include "RCS_ble_master.h"
#include "RCS_led.h"
#include "RCS_nfc.h"
#include "RCS_net.h"
#include "RCS_adc.h"
#include "RCS_station.h"
#include "bc260.h"
#include "my_wifi.h"
#include "native_ota.h"
#include "drv_eth.h"
#include "power_control.h"
/////////////////////GLOBAL VARIABLE/////////////////////
extern rcs_mast_system_t rcsSystem;

QueueHandle_t xGameQueue;
TaskHandle_t shockTaskHandle;
TaskHandle_t bleserverTaskHandle;
TaskHandle_t netTaskHandle;
TaskHandle_t heartbeatTaskHandle;
TaskHandle_t txTaskHandle;

static const char *TAG = "RCS_SYS";
static const char *SHOCK_TAG = "SHOCK_TAG";
static const char *LED_TAG = "LED_TAG";
static const char *BLE_TAG = "BLE_TAG";
static const char *NFC_TAG = "NFC_TAG";
static const char *GAME_TAG = "GAME_TAG";

/////////////////////TASK DECLAIRATION/////////////////////
// freertos任务优先级是数字越高越优先
#define POWER_CONTROL_TASK_PRIO 5
#define BLE_TASK_PRIO 11
#define IR_RX_TASK_PRIO 15
#define IR_TX_TASK_PRIO 17
#define SHOCK_TASK_PRIO 3
#define LED_TASK_PRIO 5
#define SCR_REFRESH_TASK_PRIO 7
#define GAME_TASK_PRIO 16
#define NFC_TASK_PRIO 10
#define NET_TASK_PRIO 13
#define CHECK_STA_TASK_PRIO 9

static void ir_tx_task(void *arg);
static void ble_cli_task(void *arg);

static void shock_task(void *arg);

static void led_task(void *arg);

static void scr_refresh_task(void *arg);

static void game_task(void *arg);

static void nfc_task(void *arg);

static void net_task(void *arg);
static void net_heartbeat_task(void *arg);

static void check_station_task(void *arg);

static void main_task(void *arg);

void app_main(void)
{
  // 按钮初始化
  btn_init();
  // 保持供电
  start_power_control(POWER_CONTROL_TASK_PRIO);
  /* Initialize NVS. */
  esp_err_t ret = nvs_flash_init();
  if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
  {
    ESP_ERROR_CHECK(nvs_flash_erase());
    ret = nvs_flash_init();
  }
  drv_eth_init();
  ESP_ERROR_CHECK(ret);
  xTaskCreate(main_task, "main_task", 1024 * 10, NULL, 11, NULL);
}

extern uint8_t wifi_init_finish_flag;

static void main_task(void *arg)
{
  // 创建消息队列
  xGameQueue = xQueueCreate(10, ARMOR_UPL_PACK_MAX_LEN);

  // 创建事件组，连接成功事件，被击中事件，收到遥控器命令事件
  game_event_init();

  // 电量查询初始化
  rcs_adc1_init();
  rcsSystem.equip.core.battery = rcs_adc_battery_read();
  ESP_LOGE(TAG, "core.battery:%d", rcsSystem.equip.core.battery);
  // 恢复系统信息
  remember_sys_state();
  // 蓝牙任务:
  xTaskCreate(ble_cli_task, "ble_cli_task", 1024 * 5, NULL, BLE_TASK_PRIO, &bleserverTaskHandle);

  // 基站检测任务：
  xTaskCreate(check_station_task, "check_station_task", 1024 * 10, NULL, CHECK_STA_TASK_PRIO, NULL);

  // 屏幕任务
  // xTaskCreate(scr_refresh_task, "scr_refresh_task", 1024 * 10, NULL, SCR_REFRESH_TASK_PRIO, NULL);

  // 灯光任务：
  xTaskCreate(led_task, "led_task", 1024 * 5, NULL, LED_TASK_PRIO, NULL);

  // 数据处理任务：
  xTaskCreate(game_task, "game_task", 1024 * 10, NULL, GAME_TASK_PRIO, NULL);

  // // 震动提示任务
  // xTaskCreate(shock_task, "shock_task", 1024 * 5, NULL, SHOCK_TASK_PRIO, &shockTaskHandle);

  // // NFC任务
  // xTaskCreate(nfc_task, "nfc_task", 1024 * 5, NULL, NFC_TASK_PRIO, NULL);

  // net任务:
  xTaskCreate(net_task, "net_task", 1024 * 5, NULL, NET_TASK_PRIO, &netTaskHandle);
  xTaskCreate(net_heartbeat_task, "net_heartbeat_task", 1024 * 5, NULL, NET_TASK_PRIO, &heartbeatTaskHandle);

  // 红外任务：
  xTaskCreate(rcs_ir_rx_task, "rcs_ir_rx_task", 1024 * 10, NULL, IR_RX_TASK_PRIO, NULL);
  // 红外发射任务:
  xTaskCreate(ir_tx_task, "ir_tx_task", 1024 * 10, NULL, IR_TX_TASK_PRIO, &txTaskHandle);

  ESP_LOGI(TAG, "[APP] Startup..");
  ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
  vTaskDelete(NULL);
  return;
}

/**
 * @brief: 初始化蓝牙，开启底层的蓝牙FSM(有限状态机)，
 * @param  {*}
 * @return {*}
 * @Author: TzzzT
 * @Date: 2022-04-20 00:45:02
 * @LastEditTime: Do not edit
 * @LastEditors: Shadow
 * @param {void} *arg
 */
static void ble_cli_task(void *arg)
{
  ESP_LOGI(BLE_TAG, "ble_cli_task Startup..");
  ble_mast_init();
  while (1)
  {
    // 开启扫描
    rcs_try_to_scanning(10);
    vTaskDelay(pdMS_TO_TICKS(10010));
  }
}

static void scr_refresh_task(void *arg)
{
  ESP_LOGI(BLE_TAG, "scr_refresh_task Startup..");
  notify_mask_t notify_data_mask;
  while (1)
  {
    notify_data_mask = 0;
    rcsSystem.equip.core.battery = rcs_adc_battery_read();
    if (update_low_battery_alert_flag())
    {
      // notify_data_mask |= (1 << LOW_WARNING_NOTIFY);
      // 2023 .4.17 已废弃这一项，传递电量代替了low warning
    }
    if (rcsSystem.equip.pri_weapon.screen.is_hold)
    {
      uint16_t packlen;
      notify_data_mask |= (1 << SCRBATT_NOTIFY);
      // ESP_LOGI(BLE_TAG, "SCRBATT_NOTIFY: M %2d.T %02d. S %02d. R %02d.",
      //          rcsSystem.equip.core.battery, rcsSystem.equip.pri_weapon.point.batt,
      //          rcsSystem.equip.pri_weapon.screen.batt, rcsSystem.equip.armor.batt);
      uint8_t *sync_ble_server_data = make_sync_data_package(&packlen, notify_data_mask);
      rcs_send_to_bleserver(GUN_SCREEN_CLASS, sync_ble_server_data, packlen);
      free(sync_ble_server_data);
    }
    vTaskDelay(pdMS_TO_TICKS(3000));
  }
}

#define CHECK_STA_TIME_BASE_MS 500
#define TIME_TO_COUNT(x) ((x) / 500)

#define RESOURCE_UPLOAD_INTERVAL 1500
#define DEFAULSE_UPLOAD_INTERVAL 1500
#define HP_HANDLE_INTERVAL 3000
#define SELECT_TEAM_INTERVAL 3000

static void check_station_task(void *arg)
{
  ESP_LOGI(BLE_TAG, "check_station_task Startup..");
  uint8_t time_count = 0;
  init_station_list();
  while (1)
  {
    // 更新每种基站的情况
    for (station_type_t i = 0; i < STATION_CLASS_NUM; i++)
    {
      station_list_self_subtraction(i);
    }

    if (time_count % TIME_TO_COUNT(DEFAULSE_UPLOAD_INTERVAL) == 0)
    {
      // 默认点上传
      period_upload_station(DEFAULT_STATION);
    }

    if (!rcsSystem.game.start)
    {
      if (time_count % TIME_TO_COUNT(SELECT_TEAM_INTERVAL) == 0)
      {
        select_team_by_station();
      }
    }
    else
    {
      // 先检测事件
      station_invincible_handle();
      // 游戏中
      // 占领点
      if (time_count % TIME_TO_COUNT(RESOURCE_UPLOAD_INTERVAL) == 0)
      {
        period_upload_station(RESOURCE_STATION);
      }
      if (time_count % TIME_TO_COUNT(HP_HANDLE_INTERVAL) == 0)
      {
        // 加血/扣血
        station_hp_handle();
        // 复活点
        station_reborn_handle();
      }
    }
    ++time_count;
    vTaskDelay(pdMS_TO_TICKS(CHECK_STA_TIME_BASE_MS));
  }
}

#define MS_INTERVAL(x) (x / TIME_BASE - 1)
#define TIME_BASE 50

static void ir_tx_task(void *arg)
{
  bool bullets_changed = false;
  uint16_t fire_count = 0;
  rcs_rmt_tx_init();
  player_t zero_player = {
      .id = 0,
      .damage = 0,
      .team = 0,
      .room = 0,
  };
  while (1)
  {
    if (rcsSystem.game.start)
    {
      if (!rcsSystem.game.player.living)
      {
        bullets_changed = false;
        fire_count = 0;
        ESP_LOGI(BLE_TAG, "game.start:%d, player.living:%d.Suspend ir_tx_task",
                 rcsSystem.game.start, rcsSystem.game.player.living);
        // vTaskSuspend(NULL);
        vTaskDelay(pdMS_TO_TICKS(2000));
      }
      else
      {
        if (rcsSystem.game.player.bullet_nums > 0)
        {
          if (is_pulling_trigger())
          {
            ESP_LOGI(BLE_TAG, "delay 50ms");
            vTaskDelay(pdMS_TO_TICKS(50));
            set_game_event(HIT_SUCCESS, 2);
            // 区分在固定子弹模式还是普通子弹模式
            bullet_data_set(rcsSystem.game.player.is_in_fix_bullet_mode, &(rcsSystem.game.player));
            if (rcsSystem.game.player.bullet_nums > 0 && fire(rcsSystem.game.player.is_in_fix_bullet_mode))
            {
              bullets_changed = true;
              change_player_bullet_nums(rcsSystem.game.player.bullet_nums - 1);
            }
          }
          // 1s判断一次要不要发送报文。有可能子弹在1s之内打空了，所以还是要在这里检测
          fire_count++;
          if (fire_count > MS_INTERVAL(1000))
          {
            if (bullets_changed)
            {
              fire_success_handle();
            }
            // 清空累计值。
            bullets_changed = false;
            fire_count = 0;
          }
        }
        vTaskDelay(pdMS_TO_TICKS(TIME_BASE));
      }
    }
    else
    {
      if (rcsSystem.game.player.is_in_continue_bullet_mode)
      {
        set_game_event(HIT_SUCCESS, 2);
        bullet_data_set(false, &zero_player);
        fire(false);
      }
      else if (is_pulling_trigger())
      {
        // 发射空子弹。
        set_game_event(HIT_SUCCESS, 2);
        bullet_data_set(false, &zero_player);
        fire(false);
      }
      vTaskDelay(pdMS_TO_TICKS(TIME_BASE));
    }
  }
  vTaskDelete(NULL);
}

/**
 * @brief: 初始化以后或者被唤醒以后进入while(1)循环，获取当前是否有被命中事件发生，
 *         如果有就分10次计数总共震动1s，震动完成以后挂起自身，等待红外接收到子弹或者血量改变为0时唤醒
 *         如果没有就判断是否处于死亡状态，如果是就交替震动1s,如果不是就挂起自身
 *
 *
 * @param  {*}
 * @return {*}
 * @Author: TzzzT
 * @Date: 2022-04-20 00:53:14
 * @LastEditTime: Do not edit
 * @LastEditors: Shadow
 * @param {void} *arg
 */
static void shock_task(void *arg)
{
  rcs_event_t *event;
  uint8_t dead_num = 0;
  bool state = false;
  shock_init();
  ESP_LOGI(SHOCK_TAG, "shock_task Startup..");
  while (1)
  {
    if (rcsSystem.game.start)
    {
      if (rcsSystem.game.player.living)
      {
        dead_num = 0;
        event = get_game_event_state();
        if (event->class == BE_HITTED)
        {
          set_shock(true);
          vTaskDelay(pdMS_TO_TICKS(100));
        }
        else
        {
          set_shock(false);
          vTaskSuspend(NULL);
        }
      }
      else
      { // 死亡的时候保持1s间隔的震动
        if (dead_num >= 20)
        {
          dead_num = 0;
        }
        state = (dead_num < 10) ? true : false;
        dead_num++;
        set_shock(state);
        vTaskDelay(pdMS_TO_TICKS(100));
      }
    }
    else
    {
      dead_num = 0;
      // ESP_LOGE(SHOCK_TAG, "game no start, suspend shock_task");
      set_shock(false);
      vTaskSuspend(NULL);
    }
  }
}

#define EVENT_INTERVAL 20
#define CONNECTING_INTERVAL 100

static void nfc_task(void *arg)
{
  if (nfc_init() != ESP_OK)
  {
    ESP_LOGE(NFC_TAG, "nfc_init() != ESP_OK,vTaskDelete");
    vTaskDelete(NULL);
  }
  ESP_LOGI(NFC_TAG, "nfc_task Startup..");
  while (1)
  {
    open_rc522();
    detect_tag();
    // test_add_increase_damage_tag();
    // test_add_increase_hp_tag();
    // test_add_reborn_tag();
    // test_add_increase_bulletnum_tag();
    close_rc522();
    vTaskDelay(pdMS_TO_TICKS(1000));
  }
}

static void game_task(void *arg)
{
  uint8_t package[ARMOR_UPL_PACK_MAX_LEN];
  BaseType_t xStatus;
  game_setting_init();
  ESP_LOGI(GAME_TAG, "game_task Startup..");
  while (1)
  {
    xStatus = xQueueReceive(xGameQueue, package, portMAX_DELAY);
    if (xStatus == pdPASS)
    {
      game_package_handle(package);
    }
  }
}

static void net_task(void *arg)
{
  uint8_t success_connect_before = 0;
  char user_id_ssid_str[10] = {0};
  char default_ssid_str[10] = "WENBENTEC";
  ESP_LOGE("NET_TAG", "net_task Startup..");
  net_init();
  while (!wifi_is_inited())
  {
    vTaskDelay(pdMS_TO_TICKS(1000));
  }
  itoa(rcsSystem.user.id, user_id_ssid_str, 10);
  modify_wificonfig_ssid(user_id_ssid_str);
  start_sta_wifi();
  wifi_state_t result = wifi_wait_result((_BIT(connect_failed_wifi) | _BIT(connect_success_wifi)),
                                         portMAX_DELAY);
  if (result == connect_success_wifi)
  {
    ESP_LOGE("NET_TAG", "connect success with user.id ssid");
    success_connect_before = 1;
  }
  else
  {
    ESP_LOGE("NET_TAG", "connect error , try with default ssid");

    modify_wificonfig_ssid(default_ssid_str);
    start_sta_wifi();
    result = wifi_wait_result((_BIT(connect_failed_wifi) | _BIT(connect_success_wifi)),
                              portMAX_DELAY);
    if (result == connect_success_wifi)
    {
      ESP_LOGE("NET_TAG", "connect success with default ssid");
      success_connect_before = 1;
    }
    else
    {
      ESP_LOGE("NET_TAG", "connect failed with default ssid");
    }
  }
  if (success_connect_before == 0)
  {
    vTaskDelete(NULL);
  }
  while (1)
  {
    result = wifi_wait_result(_BIT(connect_failed_wifi), portMAX_DELAY);
    set_wifi_state(nostart_wifi);
    vTaskDelay(pdMS_TO_TICKS(2000));
    start_sta_wifi();
  }
}

static void net_heartbeat_task(void *arg)
{
  ESP_LOGE("NET_TAG", "heartbeat Startup..");
  while (1)
  {
    if (rcsSystem.net.is_connected)
    {
      vTaskDelay(pdMS_TO_TICKS(10000));
      size_t message_length = 0;
      ESP_LOGI("", "send HEARTBEAT_NET_UP message to server");
      char *message = make_net_json_package(HEARTBEAT_NET_UP, &message_length, NULL);
      if (message)
      {
        net_send(message, message_length);
        free(message);
      }
      else
      {
        ESP_LOGI("send", "error, calloc failed line: %d", __LINE__);
        free(message);
      }
    }
    else
    {
      ESP_LOGE("NET_TAG", "net_heartbeat_task vTaskSuspend..");
      vTaskSuspend(NULL);
    }
  }
}

static void led_task(void *arg)
{
  rcs_event_t *event;
  uint8_t game_no_start_count = 0;
  uint8_t openning_count = 0;
  uint8_t low_battery_count = 0;
  led_t led_2 = {
      .state = true,
      .delay_time = 1000};
  led_t led_1 = {
      .state = true,
      .delay_time = 1000};
  led_init();
  ESP_LOGI(LED_TAG, "led_task Startup..");
  while (1)
  {
    // 先判断有没有事件，如果有先执行事件的显示，没有事件再根据状态显示，只会有一种事件
    event = get_game_event_state();
    if (event->class)
    {
      led_2.state = (event->count % 2 == 0) ? true : false;
      led_2.delay_time = EVENT_INTERVAL;

      if (event->class == HIT_SUCCESS ||
          event->class == BE_HITTED ||
          event->class == REMOTE_COMM_EVENT)
      {
        led_1.state = (event->count % 2 == 0) ? true : false;
      }
      else
      {
        led_1.state = 0;
      }
      update_game_event();
    }
    else
    {
      if (rcsSystem.game.start)
      {
        // 游戏开始
        if (rcsSystem.game.player.living)
        {
          // 活着
          // led_2.state = (rcsSystem.game.player.team % 2 == 1) ? true : false;
          led_2.state = false;

          led_1.state = 0;
        }
        else
        {
          // 死亡
          led_2.state = !led_2.state;
          led_2.delay_time = 500;

          led_1.state = !led_1.state;
        }
      }
      else
      {
        led_1.state = 0;
        // 游戏未开始
        if (!is_allow_open_ble_server())
        {
          // 正在连接从机
          led_2.state = (openning_count % 2 == 0) ? true : false;
          led_2.delay_time = CONNECTING_INTERVAL;
          openning_count++;
        }
        else if (rcsSystem.equip.core.battery < LOW_BATTERY)
        {
          // 低电量警告
          if (low_battery_count >= 50)
          {
            low_battery_count = 0;
          }
          if (low_battery_count < 2)
          {
            led_2.state = true;
          }
          else
          {
            led_2.state = false;
          }
          led_2.delay_time = 100;
          low_battery_count++;
        }
        else
        {
          // 普通情况
          // 有网络
          if (rcsSystem.net.is_connected)
          {
            if (game_no_start_count >= 20)
            {
              game_no_start_count = 0;
            }
            led_2.state = (game_no_start_count < 10) ? true : false;
            led_2.delay_time = 100;
            game_no_start_count++;
          }
          else
          {
            // 无网络
            if (game_no_start_count >= 40)
            {
              game_no_start_count = 0;
            }
            led_2.state = (game_no_start_count < 20) ? true : false;
            led_2.delay_time = 100;
            game_no_start_count++;
          }
        }
      }
    }
    set_led_val(LED_2_PIN, led_2.state);
    set_led_val(LED_1_PIN, led_1.state);
    vTaskDelay(pdMS_TO_TICKS(led_2.delay_time));
  }
}
